package nullInvader.Control;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import nullInvader.Engine.Tower;
import nullInvader.View.Gui;

/**
 * This Actionlistener's sole purpose is to be attached to a Swing
 * Timer by the {@link GameControl}. What it does is collect each game
 * image(Units and Textures) in the internal game grid. Then draw them
 * on the GUI's GameMapComponent.
 * 
 * @author Emanuel Yifter Lindgren (dv11elr).
 * @version 1.0
 */
public class DrawMapListener implements ActionListener {

    private final int mapHeight;
    private final int mapWidth;
    /* iconsize is used to scale the drawn images */
    private final int iconSize;

    private final BufferedImage imageFrame;
    private final BasicStroke stroke = new BasicStroke(2);

    private final Point hashKey = new Point(0, 0);

    private final GameControl gameControl;
    private final Gui gui;
    private int errorCount = 0;

    /**
     * Creates an instance of this class.
     * 
     * @param gameControl
     *            the main controller object.
     * @param gui
     *            the GUI which holds the component this listener
     *            draws on.
     * @param iconSize
     *            the size of the textures/images used in the game.
     *            This value is used to scale from the internal grid
     *            to the GUI.
     */
    public DrawMapListener(GameControl gameControl, Gui gui, int iconSize) {
        this.gameControl = gameControl;
        this.gui = gui;
        this.iconSize = iconSize;
        mapWidth = iconSize * iconSize;
        mapHeight = mapWidth;
        imageFrame = new BufferedImage(mapWidth, mapHeight,
                BufferedImage.TYPE_INT_RGB);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * java.awt.event.ActionListener#actionPerformed(java.awt.event
     * .ActionEvent)
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        errorCount = 0;

        Graphics2D graphic = imageFrame.createGraphics();

        graphic.setColor(Color.BLACK);
        graphic.fillRect(0, 0, imageFrame.getWidth(), imageFrame.getHeight());
        graphic.setStroke(stroke);
        graphic.setColor(Color.ORANGE);

        for (int y = 0; y < (mapHeight / iconSize); y++) {
            for (int x = 0; x < (mapWidth / iconSize); x++) {

                hashKey.move(x, y);

                try {
                    /* Get the brick texture image and draw it. */
                    Image texture = gameControl.getMapManager().getMap()
                            .getZone(hashKey).getBrick().getIcon();

                    /*
                     * The iconSize modifier is used to scale from
                     * internal grid coordinate to what's displayed in
                     * the GUI.
                     */
                    graphic.drawImage(texture, x * iconSize, y * iconSize,
                            null);
                } catch (NullPointerException e2) {
                    gui.promptErrorDialog(
                            "There was an error with the map at : [" + x + ","
                                    + y + "]", false);
                    errorCount++;
                    if (errorCount < 10) {
                        continue;
                    } else {
                        gui.promptErrorDialog(
                                "The map generated too many errors! Exiting.",
                                true);

                    }
                }

                try {
                    /*
                     * Only paints the first Unit for performance
                     * reasons.
                     */
                    graphic.drawImage(gameControl.getMapManager().getMap()
                            .getZone(hashKey).getUnitList().get(0).getIcon(),
                            x * iconSize, y * iconSize, null);
                } catch (IndexOutOfBoundsException e1) {
                    continue;
                } catch (NullPointerException e1) {
                    continue;
                }

            }
        }

        /*
         * Get the list of towers and draw a shot from the tower to a
         * potential target that was hit.
         */
        for (Tower twr : gameControl.getMapManager().getMap().getTowerList()) {
            Point targetPos;

            try {
                if (twr.getCurrentTarget() != null) {
                    targetPos = twr.getCurrentTarget().getPosition();

                    /*
                     * +centerModifier is needed to hit the icon in
                     * the middle.
                     */
                    int centerModifier = (iconSize / 2);
                    graphic.drawLine(
                            ((int) twr.getPosition().getX() * iconSize)
                                    + centerModifier, ((int) twr.getPosition()
                                    .getY() * iconSize) + centerModifier,
                            (int) (targetPos.getX() * iconSize)
                                    + centerModifier,
                            (int) (targetPos.getY() * iconSize)
                                    + centerModifier);
                }
            } catch (NullPointerException e1) {
                /*
                 * If the tower lost its target the shot graphic is no
                 * longer relevant and is ignored.
                 */
            }
        }

        /* Assign the buffered Image to the map component */
        gui.drawMapImage(imageFrame, 0, 0);
        graphic.dispose();
        gameControl.updatePlayerStats();
        /* Draw the assigned buffered image on the GUI component */
        gui.repaintMap();
    }
}
